/*-------------------------------------------
                Includes
-------------------------------------------*/
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <sys/file.h>
#include <sys/mman.h>
#include <linux/fb.h>
#include <opencv2/opencv.hpp>


int process_video_file(const char *fb_path,const char *video_path)
{
    // 读取视频
    cv::VideoCapture cap(video_path);
    if (!cap.isOpened())
    {
        printf("Failed to open video file: %s", video_path);
    }
    // 使用前需要使用v4l2-ctl --device=/dev/video0 --list-formats-ext检查一下设备支持范围
    cap.set(cv::CAP_PROP_FOURCC, cv::VideoWriter::fourcc('M', 'J', 'P', 'G'));
    // set width
    cap.set(cv::CAP_PROP_FRAME_WIDTH, 1920);
    // set height
    cap.set(cv::CAP_PROP_FRAME_HEIGHT, 1080);
    // set fps
    cap.set(cv::CAP_PROP_FPS,30);
    // 获取视频尺寸、帧率
    int cap_width = cap.get(cv::CAP_PROP_FRAME_WIDTH);
    int cap_height = cap.get(cv::CAP_PROP_FRAME_HEIGHT);
    int fps = cap.get(cv::CAP_PROP_FPS);

    fb_fix_screeninfo fix_screeninfo_;
    fb_var_screeninfo var_screeninfo_;
    int fd_;
    char *fb_ptr_{nullptr};

    fd_ = open(fb_path, O_RDWR);
    ioctl(fd_, FBIOGET_FSCREENINFO, &fix_screeninfo_);
    ioctl(fd_, FBIOGET_VSCREENINFO, &var_screeninfo_);
    fb_ptr_ = (char *)mmap(0, fix_screeninfo_.smem_len, PROT_READ | PROT_WRITE,
                         MAP_SHARED, fd_, 0);

    // 画面
    cv::Mat img;
    cv::Mat result;

    while (true)
    {
        // 读取视频帧
        cap >> img;
        if (img.empty())
        {
            printf("Video end.");
            break;
        }
        
        cv::resize(img, result, cv::Size(1920, 1080));
        cv::cvtColor(result, result, cv::COLOR_BGR2BGRA);
        auto dst = fb_ptr_;
        auto src = result.data;
        for (int i = 0; i < result.rows; ++i) {
            std::memcpy(dst, src, result.cols * result.elemSize());
            dst += fix_screeninfo_.line_length;
            src += result.cols * result.elemSize();
        }

    }
    // 释放资源
    cap.release();
    if (fb_ptr_ != nullptr) {
    munmap(fb_ptr_, fix_screeninfo_.smem_len);
    if (fd_) {
      flock(fd_, LOCK_UN);
      close(fd_);
    }
    fb_ptr_ = nullptr;
  }

}

int main(int argc, char **argv)
{
    int status = 0;
    int ret;

    char *fb = "/dev/fb0";
    char *video = "/dev/video0";

    process_video_file(fb,video);

    printf("waiting finish\n");
    usleep(3 * 1000 * 1000);


    return 0;
}